/* 
 * ---------------------------------------------------------------------------
 * vt_proxy License
 * ---------------------------------------------------------------------------
 * Copyright (c) 2013, Nabil S. Al Ramli, www.nalramli.com
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 *   - Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * ---------------------------------------------------------------------------
 */

static const char _NR[] = {
  0x4e,0x61,0x62,0x69,0x6c,0x20,0x53,0x2e,0x20,
  0x41,0x6c,0x20,0x52,0x61,0x6d,0x6c,0x69,0x00 };

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#include "mongoose.h"

#ifdef _WIN32
  #ifndef popen
    #define popen _popen
  #endif // popen
  #ifndef pclose
    #define pclose _pclose
  #endif // pclose
#else
  #include <sys/socket.h>
#endif
#include <curl/curl.h>
#include <curl/easy.h>

#define PROD_NAME "vt_proxy"
#define LISTENING_PORT "8080"

static char *log_path = NULL;
static FILE *log_file = NULL;
static char *replace_command_img = NULL;
static char *replace_command_pdf = NULL;
typedef size_t vt_proxy_curl_cb(
  char *ptr, size_t size, size_t nmemb, void *userdata );
char *_port;

enum VT_PROXY_OPTIONS
{
  VT_PROXY_OPTIONS_NONE = -1,
  VT_PROXY_OPTIONS_FIRST = 0,
  VT_PROXY_OPTIONS_LOG = 0,
  VT_PROXY_OPTIONS_PORT,
  VT_PROXY_OPTIONS_REPLACE_IMG,
  VT_PROXY_OPTIONS_REPLACE_PDF,
  VT_PROXY_OPTIONS_COUNT
};

void send_http_error(struct mg_connection *conn, int status,
                            const char *reason, const char *fmt, ...);

static char *vt_proxy_args[] =
{
  "--log",
  "--port",
  "--replace-img",
  "--replace-pdf",
};

typedef struct _vt_proxy_curl_cb_data
{
  // data file
  FILE *f_d;
  // header file
  FILE *f_h;
  // status to indicate if the header is finished
  int status;
} vt_proxy_curl_cb_data;

static size_t _vt_proxy_curl_cb(
  void *ptr, size_t size, size_t nmemb, void *userdata)
{
  size_t _ret = 0;
  char *_beg = (char *)ptr;
  vt_proxy_curl_cb_data *_d = (vt_proxy_curl_cb_data *)userdata;
  FILE *_f = NULL;

  if( NULL == _d )
    return 0;

  _f = _d->f_h;
  if( 1 == _d->status )
    _f = _d->f_d;
  else if( 0 == strcmp((char *)_beg, "\r\n") )
    _d->status = 1;

  if( 0 == _d->status )
  {
    if( 0 == strncmp((char *)_beg, "Connection:", strlen("Connection:")) )
    {
       fwrite("Proxy-Connection:", sizeof(char), strlen("Proxy-Connection:"), _f);
       _beg += strlen("Connection:");
       _ret += strlen("Connection:");
    }
    else if( 0 == strncmp((char *)_beg, "Transfer-Encoding:", strlen("Transfer-Encoding:")) )
      return size * nmemb;
    else if( 0 == strncmp((char *)_beg, "Content-Length:", strlen("Content-Length:")) )
      return size * nmemb;
  }

  _ret += fwrite(_beg, sizeof(char), size * nmemb - _ret, _f);
  return _ret;
}

int vt_proxy_send_request(
  const char *url, const char *qry_str,
	const char **headers, long *res, int method,
  vt_proxy_curl_cb cb, void *cb_data )
{
  // CURL object
  CURL *_curl_obj = NULL;
  // CURL return code
  CURLcode _curl_code = CURLE_OK;
  // CURL header
  struct curl_slist *_header = NULL;
  // response code
  long _res = 0;
  // download size
  double _dl_size = 0.0;
  // use SSL/
  int _is_ssl = 0;
	// final URL
	char *_url;

  if( NULL == url )
    return 1;

  if( res )
    *res = 0;

	if( qry_str && strlen(qry_str) )
		_url = (char *)calloc(strlen(url) + strlen(qry_str) + 2, sizeof(char));
	else
		_url = (char *)calloc(strlen(url) + 2, sizeof(char));
	if( NULL == _url )
		return 1;
	if( qry_str && strlen(qry_str) )
		sprintf(_url, "%s?%s", url, qry_str);
	else
		sprintf(_url, "%s", url);

  if( headers )
    while( *headers && strlen(*headers) && *(headers + 1) )
    {
      struct curl_slist *_next_header = NULL;
      char *_header_str;
      unsigned char _p_conn = 0;

      _header_str = (char *)calloc(
        strlen(*headers) + strlen(*(headers + 1)) + 3, sizeof(char) );
      if( NULL == _header_str )
      {
        curl_slist_free_all(_header);
				free(_url);
        return 1;
      }
      if( 0 == strcmp(*headers, "Proxy-Connection") )
        _p_conn = 1;
      sprintf( _header_str, "%s: %s",
        _p_conn ? "Connection" : *headers, *(headers + 1) );
      _next_header = curl_slist_append(_header, _header_str);
      free(_header_str);
      headers += 2;
      if( NULL == _next_header )
      {
        curl_slist_free_all(_header);
				free(_url);
        return 1;
      }
      else
        _header = _next_header;
    }

  if( NULL == ( _curl_obj = curl_easy_init() ) )
  {
    curl_slist_free_all(_header);
		free(_url);
    return 1;
  }

  if( 0 == strncmp(url, "https://", 8) )
    _is_ssl = 1;

  // send the url
  if( _is_ssl )
  {
    if( CURLE_OK == _curl_code )
      _curl_code = curl_easy_setopt( _curl_obj,
        CURLOPT_USE_SSL, CURLUSESSL_ALL );
    if( CURLE_OK == _curl_code )
      _curl_code = curl_easy_setopt( _curl_obj,
        CURLOPT_SSL_VERIFYPEER, 0 );
    if( CURLE_OK == _curl_code )
      _curl_code = curl_easy_setopt( _curl_obj,
        CURLOPT_SSL_VERIFYHOST, 0 );
  }
  if( CURLE_OK == _curl_code )
    _curl_code = curl_easy_setopt( _curl_obj,
      CURLOPT_URL, _url );
  if( CURLE_OK == _curl_code )
    _curl_code = curl_easy_setopt( _curl_obj,
      (CURLoption) method, 1 );
  if( CURLE_OK == _curl_code )
    _curl_code = curl_easy_setopt( _curl_obj,
      CURLOPT_HEADER, 1 );
  if( cb )
  {
    if( CURLE_OK == _curl_code ) 
      _curl_code = curl_easy_setopt( _curl_obj,
        CURLOPT_WRITEFUNCTION, cb );
  }
  if( cb_data )
  {
    if( CURLE_OK == _curl_code ) 
      _curl_code = curl_easy_setopt( _curl_obj,
        CURLOPT_WRITEDATA, cb_data );
  }
  if( _header )
  {
    if( CURLE_OK == _curl_code )
      _curl_code = curl_easy_setopt(_curl_obj,
        CURLOPT_HTTPHEADER, _header );
  }
  if( CURLE_OK == _curl_code )
    _curl_code = curl_easy_perform( _curl_obj
      );
  if( CURLE_OK == _curl_code )
    _curl_code = curl_easy_getinfo( _curl_obj,
      CURLINFO_RESPONSE_CODE, &_res );
  if( CURLE_OK == _curl_code )
    _curl_code = curl_easy_getinfo( _curl_obj,
      CURLINFO_SIZE_DOWNLOAD, &_dl_size );

  curl_slist_free_all(_header);
	free(_url);
  curl_easy_cleanup(_curl_obj);

  if( res )
    *res = _res;

  //fwrite("\r\n", 1, 2, log_file);
  if( CURLE_OK != _curl_code )
  {
    printf("Error: Internal error code: '1:%d'\n", _curl_code);
    return 1;
  }
  if( _res >= 400 )
  {
    fprintf(log_file, "Error: Request for URL: '%s' returned error code: '%d'\n", url, _res);
    return 1;
  }
  return 0;
}

static int vt_proxy_replace_img(const char *img_in, const char *img_out)
{
  char *_command = NULL;
  FILE *_pipe = NULL;
  size_t _read = 0;
  unsigned char _buf[32768];

  if( NULL == img_in || NULL == img_out )
    return 1;

  _command = (char *)calloc(
    sizeof(char), strlen(img_in) + strlen(img_out) + 2048 );
  if( NULL == _command )
    return 1;
  strcpy(_command, replace_command_img);
  strcat(_command, " -f \"");
  strcat(_command, img_in);
  strcat(_command, "\"");
  strcat(_command, " -o \"");
  strcat(_command, img_out);
  strcat(_command, "\"");
  fprintf(log_file, "%s\n", _command);
  _pipe = popen(_command, "r");
  if( _pipe )
  {
    while( _read = fread(_buf, sizeof(char), 32768, _pipe) );
    pclose(_pipe);
  }
  else
  {
    fprintf(log_file, "Error: failed to execute '%s'.\n", _command);
    free(_command);
    return 1;
  }
  free(_command);
  return 0;
}

static int vt_proxy_replace_pdf(const char *pdf_in, const char *pdf_out)
{
  char *_command = NULL;
  FILE *_pipe = NULL;
  size_t _read = 0;
  unsigned char _buf[32768];

  if( NULL == pdf_in || NULL == pdf_out )
    return 1;

  _command = (char *)calloc(
    sizeof(char), strlen(pdf_in) + strlen(pdf_out) + 2048 );
  if( NULL == _command )
    return 1;
  strcpy(_command, replace_command_pdf);
  strcat(_command, " \"");
  strcat(_command, pdf_in);
  strcat(_command, "\"");
  strcat(_command, " \"");
  strcat(_command, pdf_out);
  strcat(_command, "\"");
  fprintf(log_file, "%s\n", _command);
  _pipe = popen(_command, "r");
  if( _pipe )
  {
    while( _read = fread(_buf, sizeof(char), 32768, _pipe) );
    pclose(_pipe);
  }
  else
  {
    fprintf(log_file, "Error: failed to execute '%s'.\n", _command);
    free(_command);
    return 1;
  }
  free(_command);
  return 0;
}

static void *vt_proxy_mg_cb(enum mg_event event_,
  struct mg_connection *conn,
  const struct mg_request_info *request_info)
{
  time_t _curtime = time(NULL);
  char _curtime_str[64];
  const size_t _buf_len = 32768;
  unsigned char _buf[32768];
  long _res = 0;

  strftime( _curtime_str, 64, "%a, %d %b %Y %H:%M:%S GMT",
  gmtime( &_curtime ) );

  switch( event_ )
  {
  case MG_NEW_REQUEST:
    if( request_info->query_string && strlen(request_info->query_string) )
      fprintf(log_file, "%s '%s?%s'\n", request_info->request_method, request_info->uri, request_info->query_string);
    else
      fprintf(log_file, "%s '%s'\n", request_info->request_method, request_info->uri);

    if( 0 == strcmp("POST", request_info->request_method) )
    {
      vt_proxy_send_request(
        request_info->uri, request_info->query_string,
        (const char **)request_info->http_headers,
        &_res, CURLOPT_POST, NULL, NULL );
      return 0;
    }
    else if( 0 == strcmp("GET", request_info->request_method) ||
      0 == strcmp("HEAD", request_info->request_method) )
    {
      vt_proxy_curl_cb_data _d;
      FILE *_f_d = NULL, *_f_h = NULL;
      char _read_buf[4*1024] = "", *_n_d = NULL, *_n_h = NULL;
      size_t _read_len = 0;

      _n_d = tempnam(".", PROD_NAME);
      if( NULL == _n_d )
      {
        fprintf(log_file, "Error: Failed to generate temporary file name\n");
        return 0;
      }
      _f_d = fopen(_n_d, "w+b");
      if( NULL == _f_d )
      {
        fprintf(log_file, "Error: Failed to open '%s'\n", _n_d);
        return 0;
      }
      _n_h = tempnam(".", PROD_NAME);
      if( NULL == _n_h )
      {
        fprintf(log_file, "Error: Failed to generate temporary file name\n");
        return 0;
      }
      _f_h = fopen(_n_h, "w+b");
      if( NULL == _f_h )
      {
        fprintf(log_file, "Error: Failed to open '%s'\n", _n_h);
        return 0;
      }
      memset(&_d, 0, sizeof(_d));
      _d.f_d = _f_d;
      _d.f_h = _f_h;
      vt_proxy_send_request(
        request_info->uri, request_info->query_string,
				(const char **)request_info->http_headers,
        &_res, CURLOPT_HTTPGET, _vt_proxy_curl_cb, &_d );
      // first send the header as is
      if( 0 != fseek(_f_h, 0, SEEK_SET) )
      {
        fprintf(log_file, "Error: Failed to seek to beginning of '%s'\n", _n_h);
        if( _f_h )
        {
          fclose(_f_h);
          _f_h = NULL;
        }
        remove(_n_h);
        if( _f_d )
        {
          fclose(_f_d);
          _f_d = NULL;
        }
        remove(_n_d);
        return 0;
      }
      while( _read_len = fread(_read_buf, sizeof(char), 4*1024, _f_h) )
        if( _read_len != mg_write(conn, _read_buf, _read_len) )
        {
          fprintf( log_file, "Error: Failed to send '%s'\n",
            request_info->uri );
          break;
        }
      if( _f_h )
      {
        fclose(_f_h);
        _f_h = NULL;
      }
      remove(_n_h);
      // next send the content, possibly modified
      if( 0 != fseek(_f_d, 0, SEEK_SET) )
      {
        fprintf(log_file, "Error: Failed to seek to beginning of '%s'\n", _n_d);
        if( _f_d )
        {
          fclose(_f_d);
          _f_d = NULL;
        }
        remove(_n_d);
        return 0;
      }
      if(
          strstr(request_info->uri, "pdf") ||
          strstr(request_info->uri, "PDF")
        )
      {
        FILE *_f_r = NULL;
        char *_n_r = NULL;

        if( _f_d )
        {
          fclose(_f_d);
          _f_d = NULL;
        }
        _n_r = tempnam(".", PROD_NAME);
        if( NULL == _n_r )
        {
          fprintf(log_file, "Error: Failed to generate temporary file name\n");
          return 0;
        }

        vt_proxy_replace_pdf(_n_d, _n_r);
        _f_r = fopen(_n_r, "rb");
        if( NULL == _f_r )
	        _f_r = fopen(_n_d, "rb");
        if( NULL == _f_r )
        {
          fprintf(log_file, "Error: Failed to open '%s'\n", _n_r);
          remove(_n_d);
          return 0;
        }
        // read the modified content
        while( _read_len = fread(_read_buf, sizeof(char), 4*1024, _f_r) )
          if( _read_len != mg_write(conn, _read_buf, _read_len) )
          {
            fprintf(_f_r, "Error: Failed to send '%s'\n", _n_r);
            break;
          }
        if( _f_r )
        {
          fclose(_f_r);
          _f_r = NULL;
        }
        remove(_n_r);
        remove(_n_d);
      }
      else if(
          strstr(request_info->uri, "jpg") ||
          strstr(request_info->uri, "JPG") ||
          strstr(request_info->uri, "jpeg") ||
          strstr(request_info->uri, "JPEG") ||
          strstr(request_info->uri, "png") ||
          strstr(request_info->uri, "PNG") ||
          strstr(request_info->uri, "bmp") ||
          strstr(request_info->uri, "BMP") ||
          strstr(request_info->uri, "gif") ||
          strstr(request_info->uri, "GIF") ||
          strstr(request_info->uri, "tif") ||
          strstr(request_info->uri, "TIF") ||
          strstr(request_info->uri, "img") ||
          strstr(request_info->uri, "IMG") ||
          strstr(request_info->uri, "image") ||
          strstr(request_info->uri, "IMAGE")
        )
      {
        FILE *_f_r = NULL;
        char *_n_r = NULL;

        if( _f_d )
        {
          fclose(_f_d);
          _f_d = NULL;
        }
        _n_r = tempnam(".", PROD_NAME);
        if( NULL == _n_r )
        {
          fprintf(log_file, "Error: Failed to generate temporary file name\n");
          return 0;
        }

        vt_proxy_replace_img(_n_d, _n_r);
        _f_r = fopen(_n_r, "rb");
        if( NULL == _f_r )
	        _f_r = fopen(_n_d, "rb");
        if( NULL == _f_r )
        {
          fprintf(log_file, "Error: Failed to open '%s'\n", _n_r);
          remove(_n_d);
          return 0;
        }
        // read the modified content
        while( _read_len = fread(_read_buf, sizeof(char), 4*1024, _f_r) )
          if( _read_len != mg_write(conn, _read_buf, _read_len) )
          {
            fprintf(_f_r, "Error: Failed to send '%s'\n", _n_r);
            break;
          }
        if( _f_r )
        {
          fclose(_f_r);
          _f_r = NULL;
        }
        remove(_n_r);
        remove(_n_d);
      }
      else
      {
        while( _read_len = fread(_read_buf, sizeof(char), 4*1024, _f_d) )
          if( _read_len != mg_write(conn, _read_buf, _read_len) )
          {
            fprintf( log_file, "Error: Failed to send '%s'\n",
              request_info->uri );
            break;
          }
      }
      if( _f_d )
      {
        fclose(_f_d);
        _f_d = NULL;
      }
      remove(_n_d);
      return (void *)1;
    }

    break;

  case MG_HTTP_ERROR:
    fprintf( log_file, "Error: '%s' returned '%d'\n",
      request_info->uri, request_info->status_code );
    break;

  case MG_EVENT_LOG:
    fprintf( log_file, "Error: '%s' returned '%s'\n",
      request_info->uri, request_info->log_message );
    break;

  case MG_INIT_SSL:
    break;

  case MG_REQUEST_COMPLETE:
    /*
    fprintf( log_file, "Request to '%s' completed\n",
      request_info->uri, request_info->status_code );
     */
    break;

  default:
    break;
  }
  return NULL;
}

static void vt_proxy_usage()
{
  fprintf(log_file,  "\n**************************************************\n\n" );
  fprintf(log_file, "%s\n\n", PROD_NAME);
  fprintf(log_file, "Usage:\n\n");
  fprintf(log_file, "  %s [options] [required_options]\n\n", PROD_NAME);
  fprintf(log_file, "options:\n\n");
  fprintf(log_file, "  %s <log_path>\n\n", vt_proxy_args[VT_PROXY_OPTIONS_LOG] );
  fprintf(log_file, "  %s <port>\n\n", vt_proxy_args[VT_PROXY_OPTIONS_PORT] );
  fprintf(log_file, "required_options:\n\n");
  fprintf(log_file, "  %s <replace_command_img>\n\n", vt_proxy_args[VT_PROXY_OPTIONS_REPLACE_IMG] );
  fprintf(log_file, "  %s <replace_command_pdf>\n\n", vt_proxy_args[VT_PROXY_OPTIONS_REPLACE_PDF] );
  fprintf(log_file, "**************************************************\n\n" );
}

static void vt_proxy_cleanup()
{
  if( log_path )
  {
    if( log_file )
      fclose( log_file );
    log_path = NULL;
  }
  log_file = stderr;
  replace_command_img = NULL;
  remove(PROD_NAME".tmp");
}

int vt_proxy_set_default_args()
{
  log_path = NULL;
  log_file = stderr;
  replace_command_img = NULL;
  _port = LISTENING_PORT;
  return 0;
}

int vt_proxy_get_args(int argc, char** argv)
{
  int _i;
  
  if( argc < 2 )
  {
    vt_proxy_usage();
    return 1;
  }

  // first pass
  for( _i = 1; _i < argc; _i++ )
  {
    if
    (
        0 == strcmp(argv[_i], "help") ||
        0 == strcmp(argv[_i] + 1, "help") ||
        0 == strcmp(argv[_i] + 2, "help") ||
        0 == strcmp(argv[_i], "h") ||
        0 == strcmp(argv[_i] + 1, "h") ||
        0 == strcmp(argv[_i] + 1, "-h")
    )
    {
      vt_proxy_usage();
      return 0;
    }

    if( strlen( argv[_i] ) < 2 )
    {
      vt_proxy_usage();
      fprintf(log_file, "Error: Invalid option '%s'.\n", argv[_i]);
      return 1;
    }      
        
    if( 0 == strcmp( argv[_i], vt_proxy_args[VT_PROXY_OPTIONS_LOG] ) )
    {
      _i++;
      if( _i < argc )
      {
        log_path = argv[_i];
        log_file = fopen(log_path, "ab");
        if( NULL == log_file )
        {
          fprintf( stderr, "Error: failed to open file '-%s' for logging.\n",
            log_path );
          return 1;
        }
      }
      else
      {
        vt_proxy_usage();
        fprintf( log_file, "Error: No value specified for '-%s'.\n",
          vt_proxy_args[VT_PROXY_OPTIONS_LOG] );
        return 1;
      }
    }
    else if( 0 == strcmp( argv[_i], vt_proxy_args[VT_PROXY_OPTIONS_PORT] ) )
    {
      _i++;
      if( _i < argc )
      {
        _port = argv[_i];
      }
      else
      {
        vt_proxy_usage();
        fprintf( log_file, "Error: No value specified for '-%s'.\n",
          vt_proxy_args[VT_PROXY_OPTIONS_PORT] );
        return 1;
      }
    }
    else if( 0 == strcmp( argv[_i], vt_proxy_args[VT_PROXY_OPTIONS_REPLACE_IMG] ) )
    {
      _i++;
      if( _i < argc )
      {
        replace_command_img = argv[_i];
      }
      else
      {
        vt_proxy_usage();
        fprintf( log_file, "Error: No value specified for '-%s'.\n",
          vt_proxy_args[VT_PROXY_OPTIONS_REPLACE_IMG] );
        return 1;
      }
    }
    else if( 0 == strcmp( argv[_i], vt_proxy_args[VT_PROXY_OPTIONS_REPLACE_PDF] ) )
    {
      _i++;
      if( _i < argc )
      {
        replace_command_pdf = argv[_i];
      }
      else
      {
        vt_proxy_usage();
        fprintf( log_file, "Error: No value specified for '-%s'.\n",
          vt_proxy_args[VT_PROXY_OPTIONS_REPLACE_PDF] );
        return 1;
      }
    }
  }

  if( NULL == replace_command_img )
  {
    vt_proxy_usage();
    fprintf( log_file, "Error: '-%s' is required.\n",
      vt_proxy_args[VT_PROXY_OPTIONS_REPLACE_IMG] );
    return 1;
  }
  if( NULL == replace_command_pdf )
  {
    vt_proxy_usage();
    fprintf( log_file, "Error: '-%s' is required.\n",
      vt_proxy_args[VT_PROXY_OPTIONS_REPLACE_PDF] );
    return 1;
  }
  
  return 0;
}

/*
 * 
 */
int main(int argc, char** argv)
{
  struct mg_context *_mg_ctx = NULL;
  const char **_options = NULL;

  if( vt_proxy_set_default_args() )
  {
    vt_proxy_cleanup();
    return 1;
  }
  
  if( vt_proxy_get_args(argc, argv) )
  {
    vt_proxy_cleanup();
    return 1;
  }

  if( CURLE_OK != curl_global_init(CURL_GLOBAL_ALL) )
  {
    vt_proxy_cleanup();
    return 1;
  }

  _options = (char **)calloc(9, sizeof(char *));
  if( NULL == _options )
  {
    fprintf(log_file, "Error: Failed to allocate memory.\n");
    return 1;
  }
  _options[0] = "listening_ports";
  _options[1] = _port;
  _options[2] = "error_log_file";
  _options[3] = "error.log";
  _options[4] = "access_log_file";
  _options[5] = "access.log";
  /*
  _options[6] = "ssl_certificate";
  _options[7] = "ssl.pem";
  */
  _options[8] = NULL;
  _mg_ctx = mg_start(vt_proxy_mg_cb, NULL, _options);
  free( _options );
  if( _mg_ctx )
  {
    fprintf(log_file, "\nPress return to stop the server.\n");
    getchar();
  }
  else
    fprintf(log_file, "Error: Failed to start the server.\n");

  vt_proxy_cleanup();
  return 0;
}
